﻿package 
{
	import com.bit101.components.Label;
	import com.bit101.components.MinimalComps;
	import com.bit101.components.PushButton;
	import flash.accessibility.AccessibilityImplementation;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import graph.Graph;
	import graph.Node;
	import twitter.*;
	import components.*;

	/**
	 * ...
	 * @author s
	 */
    [SWF(width = "640", height = "640", frameRate = "60")]
	public class Main extends Sprite 
	{
		private var _tweetLoader:TweetLoaderFriendTimeline;
		private var _twitterAccessToken:String;
		private var _twitterAccessTokenSecret:String;
		private var _node2TweetArray:Object;
		
		private var _lastLoadedWords:Array;
		private var _graph:Graph;
		
		private var _lastClickedNode:Node;
		private var _lastFocusedTweet:Tweet;
		
		//components
		private var _initIndicatorLabel:Label;
		private var _initIndicatorBarSize:int;
		private var _fisheyeGraphView:FisheyeGraphView;
		//private var _tweetList:FisheyeListBox;
		private var _tweetList:ListBox;
		private var _tweetListPanel:ZipPanel;
		private var _showAllButton:PushButton;
		
		private const INIT_TWEETS_COUNT:int = 50;
		private const INIT_INDICATOR_LABEL:String = "Initializing...";
		private const LOAD_TWEETS_TASK_NAME:String = "Load last 50 tweets from your friend_timeline";
		
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			InitJobCounter.getInstance().addEventListener(InitJobCounter.COMPLETE, onCompleteInitJobs);
			InitJobCounter.getInstance().addEventListener(InitJobCounter.DOWN, onInitJobCounterChange);
			InitJobCounter.getInstance().addEventListener(InitJobCounter.UP, onInitJobCounterChange);
			
			var flashVars:Object = this.loaderInfo.parameters;
			_twitterAccessToken = flashVars["twitterAccessToken"];
			_twitterAccessTokenSecret = flashVars["twitterAccessTokenSecret"]
			_tweetLoader = new TweetLoaderFriendTimeline(_twitterAccessToken, _twitterAccessTokenSecret, TwitterKey.CONSUMER_KEY, TwitterKey.CONSUMER_SECRET);
			_tweetLoader.addEventListener(TweetEvent.LOAD, onLoadNewTweet, false, 1);
			_tweetLoader.addEventListener(TweetEvent.COMPLETE, onCompleteLoadTweets, false, 1);
			_tweetLoader.loadFriendTimeline(INIT_TWEETS_COUNT);
			
			_graph = new Graph();
			_lastLoadedWords = new Array;
			_node2TweetArray = new Object;
			
			_lastClickedNode = null;
			_lastFocusedTweet = null;
			
			initComponents();

			InitJobCounter.getInstance().up(LOAD_TWEETS_TASK_NAME);

			//addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0);
		}
		
		private function initComponents():void 
		{
			const VIEWER_MARGIN:int = 20;
			_fisheyeGraphView = new FisheyeGraphView(
				VIEWER_MARGIN, VIEWER_MARGIN,
				stage.stageWidth - VIEWER_MARGIN * 2, stage.stageHeight - VIEWER_MARGIN * 2, _graph
			);
			_fisheyeGraphView.addEventListener(FisheyeGraphView.MOUSE_EVENT_CLICK_NODE, onClickGraphNode);
			_fisheyeGraphView.visible = false;
			this.addChild(_fisheyeGraphView);
			
			const PANEL_LEFT:int = 4;
			const PANEL_ZIPPED_WIDTH:int = 100;
			const PANEL_EXPANDED_WIDTH:int = stage.stageWidth - PANEL_LEFT * 2;
			const PANEL_ZIPPED_HEIGHT:int = 20;
			const PANEL_EXPANDED_HEIGHT:int = stage.stageHeight * 0.35;
			const PANEL_BOTTOM_MARGIN:int = 4;
			_tweetListPanel = new ZipPanel(
				"TWEETS",
				new Rectangle(PANEL_LEFT, stage.stageHeight - PANEL_ZIPPED_HEIGHT - PANEL_BOTTOM_MARGIN,
								PANEL_ZIPPED_WIDTH, PANEL_ZIPPED_HEIGHT),
				new Rectangle(PANEL_LEFT, stage.stageHeight - PANEL_EXPANDED_HEIGHT - PANEL_BOTTOM_MARGIN,
								PANEL_EXPANDED_WIDTH, PANEL_EXPANDED_HEIGHT)
			);
			_tweetListPanel.alpha = 0.6;
			_tweetListPanel.visible = false;
			this.addChild(_tweetListPanel);
			
			const LIST_LEFT:int = 10;
			const LIST_TOP:int = 26;
			const LIST_WIDTH:int = PANEL_EXPANDED_WIDTH - LIST_LEFT * 2;
			const LIST_HEIGHT:int = PANEL_EXPANDED_HEIGHT - LIST_TOP - 10;
			//_tweetList = new FisheyeListBox(_tweetListPanel, LIST_LEFT, LIST_TOP, LIST_WIDTH, LIST_HEIGHT);
			_tweetList = new ListBox(_tweetListPanel.content, LIST_LEFT, LIST_TOP, LIST_WIDTH, LIST_HEIGHT / ListBox.ITEM_HEIGHT);

			_initIndicatorBarSize = 0;
			MinimalComps.setLanguage(MinimalComps.JAPANESE);
			_initIndicatorLabel = new Label(this, 0, 0, INIT_INDICATOR_LABEL);
			_initIndicatorLabel.x = 10;
			_initIndicatorLabel.y = 20;
			MinimalComps.setLanguage(MinimalComps.JAPANESE);
		}
		

		//
		// 新しくTweetをロードしたときに呼ばれるイベントハンドラ
		//
		private const _STOPWORD:Object = {
			'RT': true
		}

		private function onLoadNewTweet(e:TweetEvent):void 
		{
			
			var tweet:Tweet = e.tweet;
			var buf:String = tweet.text;
			buf = buf.replace(/@[a-zA-Z0-9]*/g, ""); // remove user name
			buf = buf.replace(/(https?|ftp)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)/, "");  // remove url

			var words:Array = buf.match(/([一-龠々〆ヵヶ]+)|([ァ-ヴー－―]+)|([a-zA-ZａｚＡ-Ｚ]+)/g);
			words = words.filter(function (buf:String, index:int, arr:Array):Boolean 
			{
				return !(buf.match(/^[ー－―]+$/) || buf.length == 1);
			});
			
			for each (var word:String in words) {
				if (_STOPWORD[word] != undefined) {
					continue;
				}
				var node:Node = _graph.nodeByLabel(word);
				if(node == null){
					node = new Node(word, 1.0);
					_graph.addNode(node);
					_fisheyeGraphView.addNewNode(node);
				}
				
				// add to node2TweetArray
				if (_node2TweetArray[node.id.toString()] == undefined) {
					_node2TweetArray[node.id.toString()] = new Array;
				}
				_node2TweetArray[node.id.toString()].push(tweet);
				
				var dstNodeLabel:String
				for each (dstNodeLabel in words) {
					if (dstNodeLabel == word) {
						break;
					}
					if(_graph.nodeByLabel(dstNodeLabel) != null){
						_graph.defineNewEdge(node, _graph.nodeByLabel(dstNodeLabel), 1.0);
					}
				}
				for each (dstNodeLabel in _lastLoadedWords) {
					if(_graph.nodeByLabel(dstNodeLabel) != null){
						_graph.defineNewEdge(node, _graph.nodeByLabel(dstNodeLabel), 0.1);
					}
				}
			}
			_lastLoadedWords = words;
			_tweetList.unshift(tweet.userScreenName + " : " + tweet.text, tweet.id);
		}
		
		
		private function onEnterFrameForFadeinFisheyeGraphView(e:Event):void
		{
			_fisheyeGraphView.alpha += 0.05;
			if (_fisheyeGraphView.alpha >= 1.0) {
				_fisheyeGraphView.alpha = 1.0;
				this.removeEventListener(Event.ENTER_FRAME, onEnterFrameForFadeinFisheyeGraphView);
			}
		}
		
		private function onCompleteLoadTweets(e:TweetEvent):void 
		{
			InitJobCounter.getInstance().down(LOAD_TWEETS_TASK_NAME);
		}
		
		private function onCompleteInitJobs(e:Event):void 
		{
			this.graphics.clear();  // clear indicator bar
			removeChild(_initIndicatorLabel);
			_fisheyeGraphView.alpha = 0.0;
			_fisheyeGraphView.visible = true;
			_fisheyeGraphView.activate();
			this.addEventListener(Event.ENTER_FRAME, onEnterFrameForFadeinFisheyeGraphView);
			_tweetListPanel.visible = true;
		}
		
		private function onInitJobCounterChange(e:Event):void 
		{
			this.graphics.clear();
			this.graphics.beginFill(0x808080);
			this.graphics.drawRect(_initIndicatorLabel.x, _initIndicatorLabel.y - 4,
									_initIndicatorBarSize, 2);
			this.graphics.endFill();
			_initIndicatorLabel.text = INIT_INDICATOR_LABEL + "\nRemain tasks\n  "
										+ InitJobCounter.getInstance().remainTasks.join("\n  ");
			_initIndicatorBarSize += 1;
		}
		
		private function onClickGraphNode(e:Event):void 
		{
			var node:Node = (e.target as FisheyeGraphView).clickedNode;
			
			if (!_tweetList.inAutoScroll && _node2TweetArray[node.id.toString()] != undefined) {
				_tweetList.unhighlightAll();
				
				var ary:Array = _node2TweetArray[node.id.toString()] as Array;
				for (var i:int = 0; i < ary.length; i++) {
					var tweet:Tweet = ary[i] as Tweet;
					_tweetList.highlightItem(tweet.id);
				}
				if (_lastClickedNode == node) {
					if(ary.length >= 2){
						_lastFocusedTweet = ary[(ary.indexOf(_lastFocusedTweet) + 1) % ary.length];
					}
				}
				else {
					_lastFocusedTweet = ary[0];
				}
				_tweetList.focusItem(_lastFocusedTweet.id);
				_lastClickedNode = node;
				
				_tweetList.updateContents();
				_tweetListPanel.expand();
			}
		}
	}
}
